Make XEN_DOMCTL_destroydomain hypercall preemptible, in a way that is
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Fri, 31 Aug 2007 14:44:38 +0000 (15:44 +0100)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Fri, 31 Aug 2007 14:44:38 +0000 (15:44 +0100)
visible to the caller (via -EAGAIN return code).

This prevents softlockup in dom0 kernel, due to the hypercall taking
too long to execute on very large (multi-multi-gigabyte) domains.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/ia64/xen/domain.c
xen/arch/powerpc/domain.c
xen/arch/x86/domain.c
xen/common/domain.c
xen/common/domctl.c
xen/include/asm-ia64/domain.h
xen/include/xen/domain.h
xen/include/xen/sched.h

index 1cda521a4ecf36d6c1472eea045a2e495272fc5b..7914a81406bad9cf20f737e7e953e5f6574b9025 100644 (file)
@@ -936,7 +936,7 @@ static void relinquish_memory(struct domain *d, struct list_head *list)
     spin_unlock_recursive(&d->page_alloc_lock);
 }
 
-void domain_relinquish_resources(struct domain *d)
+int domain_relinquish_resources(struct domain *d)
 {
     /* Relinquish guest resources for VT-i domain. */
     if (d->vcpu[0] && VMX_DOMAIN(d->vcpu[0]))
@@ -954,6 +954,8 @@ void domain_relinquish_resources(struct domain *d)
 
     /* Free page used by xen oprofile buffer */
     free_xenoprof_pages(d);
+
+    return 0;
 }
 
 unsigned long
index 312fffdab253b221983d083a23078244d25bb558..c0f78bf797685b11ed49bee6b0eb9726d7465dd0 100644 (file)
@@ -313,13 +313,13 @@ static void relinquish_memory(struct domain *d, struct list_head *list)
     spin_unlock_recursive(&d->page_alloc_lock);
 }
 
-void domain_relinquish_resources(struct domain *d)
+int domain_relinquish_resources(struct domain *d)
 {
     relinquish_memory(d, &d->xenpage_list);
     relinquish_memory(d, &d->page_list);
     xfree(d->arch.foreign_mfns);
     xfree(d->arch.p2m);
-    return;
+    return 0;
 }
 
 void arch_dump_domain_info(struct domain *d)
index 0f4077f48cf81f3dde2127de26e9842eb565b159..203ca8ba2a663abdfc6f60cbf0d70155101a1f86 100644 (file)
@@ -1717,7 +1717,7 @@ static void vcpu_destroy_pagetables(struct vcpu *v)
     v->arch.cr3 = 0;
 }
 
-void domain_relinquish_resources(struct domain *d)
+int domain_relinquish_resources(struct domain *d)
 {
     struct vcpu *v;
 
@@ -1754,6 +1754,8 @@ void domain_relinquish_resources(struct domain *d)
 
     if ( is_hvm_domain(d) )
         hvm_domain_relinquish_resources(d);
+
+    return 0;
 }
 
 void arch_dump_domain_info(struct domain *d)
index 0e48eeeda48fd304b83906753c13b96fa2a3783a..a470cc8e73ab6aac489247283a63b5ecedb4dfcc 100644 (file)
@@ -245,7 +245,7 @@ struct domain *domain_create(
     return d;
 
  fail:
-    d->is_dying = 1;
+    d->is_dying = DOMDYING_dead;
     atomic_set(&d->refcnt, DOMAIN_DESTROYED);
     if ( init_status & INIT_arch )
         arch_domain_destroy(d);
@@ -303,26 +303,37 @@ struct domain *rcu_lock_domain_by_id(domid_t dom)
 }
 
 
-void domain_kill(struct domain *d)
+int domain_kill(struct domain *d)
 {
-    domain_pause(d);
+    int rc = 0;
+
+    if ( d == current->domain )
+        return -EINVAL;
 
-    /* Already dying? Then bail. */
-    if ( test_and_set_bool(d->is_dying) )
+    /* Protected by domctl_lock. */
+    switch ( d->is_dying )
     {
-        domain_unpause(d);
-        return;
+    case DOMDYING_alive:
+        domain_pause(d);
+        d->is_dying = DOMDYING_dying;
+        evtchn_destroy(d);
+        gnttab_release_mappings(d);
+    case DOMDYING_dying:
+        rc = domain_relinquish_resources(d);
+        page_scrub_kick();
+        if ( rc != 0 )
+        {
+            BUG_ON(rc != -EAGAIN);
+            break;
+        }
+        d->is_dying = DOMDYING_dead;
+        put_domain(d);
+        send_guest_global_virq(dom0, VIRQ_DOM_EXC);
+    case DOMDYING_dead:
+        break;
     }
 
-    evtchn_destroy(d);
-    gnttab_release_mappings(d);
-    domain_relinquish_resources(d);
-    put_domain(d);
-
-    /* Kick page scrubbing after domain_relinquish_resources(). */
-    page_scrub_kick();
-
-    send_guest_global_virq(dom0, VIRQ_DOM_EXC);
+    return rc;
 }
 
 
index 0b13cd9f69d1771bc9c3520ea375fa6ef94b0f54..6ef83e8fd2c1af1b29b1c87d63ca3ea76c236ee4 100644 (file)
@@ -114,10 +114,10 @@ void getdomaininfo(struct domain *d, struct xen_domctl_getdomaininfo *info)
     info->cpu_time = cpu_time;
 
     info->flags = flags |
-        (d->is_dying                ? XEN_DOMINF_dying    : 0) |
-        (d->is_shut_down            ? XEN_DOMINF_shutdown : 0) |
-        (d->is_paused_by_controller ? XEN_DOMINF_paused   : 0) |
-        (d->debugger_attached       ? XEN_DOMINF_debugged : 0) |
+        ((d->is_dying == DOMDYING_dead) ? XEN_DOMINF_dying    : 0) |
+        (d->is_shut_down                ? XEN_DOMINF_shutdown : 0) |
+        (d->is_paused_by_controller     ? XEN_DOMINF_paused   : 0) |
+        (d->debugger_attached           ? XEN_DOMINF_debugged : 0) |
         d->shutdown_code << XEN_DOMINF_shutdownshift;
 
     if ( is_hvm_domain(d) )
@@ -422,18 +422,7 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
         ret = -ESRCH;
         if ( d != NULL )
         {
-            ret = xsm_destroydomain(d);
-            if ( ret )
-                goto destroydomain_out;
-
-            ret = -EINVAL;
-            if ( d != current->domain )
-            {
-                domain_kill(d);
-                ret = 0;
-            }
-
-        destroydomain_out:
+            ret = xsm_destroydomain(d) ? : domain_kill(d);
             rcu_unlock_domain(d);
         }
     }
index 6a8af521f9846c85442e9bf420e926e4bdbac46e..40bc6e52adb4010cf5e100ff8e50a2ac14d7b711 100644 (file)
@@ -18,7 +18,6 @@ struct p2m_entry;
 struct tlb_track;
 #endif
 
-extern void domain_relinquish_resources(struct domain *);
 struct vcpu;
 extern void relinquish_vcpu_resources(struct vcpu *v);
 extern void vcpu_share_privregs_with_guest(struct vcpu *v);
index dd19c966b7eca9fa9d4db78cc0dd1b10ade6b140..aa8c72f0ac42a2e7ac07cb46fdb969e428e55835 100644 (file)
@@ -45,7 +45,7 @@ void arch_domain_destroy(struct domain *d);
 int arch_set_info_guest(struct vcpu *, vcpu_guest_context_u);
 void arch_get_info_guest(struct vcpu *, vcpu_guest_context_u);
 
-void domain_relinquish_resources(struct domain *d);
+int domain_relinquish_resources(struct domain *d);
 
 void dump_pageframe_info(struct domain *d);
 
index 9135ca3b44ccde7976f67a3af488134a5bc125ee..f863f4a837e4b0d8382ae17d07f7bc691e8a032c 100644 (file)
@@ -194,7 +194,7 @@ struct domain
     /* Are any VCPUs polling event channels (SCHEDOP_poll)? */
     bool_t           is_polling;
     /* Is this guest dying (i.e., a zombie)? */
-    bool_t           is_dying;
+    enum { DOMDYING_alive, DOMDYING_dying, DOMDYING_dead } is_dying;
     /* Domain is paused by controller software? */
     bool_t           is_paused_by_controller;
 
@@ -338,7 +338,7 @@ static inline struct domain *rcu_lock_current_domain(void)
 
 struct domain *get_domain_by_id(domid_t dom);
 void domain_destroy(struct domain *d);
-void domain_kill(struct domain *d);
+int domain_kill(struct domain *d);
 void domain_shutdown(struct domain *d, u8 reason);
 void domain_resume(struct domain *d);
 void domain_pause_for_debugger(void);